﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TextDungeon
{
    public enum CellType { Start, End, Treasure, Other }
    class Cell
    {

        Position WorldPos;
        public List<Entity> walls = new List<Entity>();
        public CellType ct = CellType.Other;
        public int squareWidth = 30;
        public int squareHeight = 20;
        public GUI gui = new GUI();


        /// <summary>
        /// creates a cell or level in world
        /// </summary>
        /// <param name="t">what type of cell or what type of </param>
        /// <param name="Offset">this will be removed in due time, i must first complete ranomized generatoin first</param>
        public Cell(CellType t)
        {
            
            ct = t;
            MakeCell();
            gui.WriteAt(walls.Count.ToString(), new Position(50, 5));

        }

        public byte[] DirectionsAllowed(Position pos) 
        {
            var b = new byte[4];
            byte a = 0;
            for (byte i = 0; i < b.Length; i++)
            {
                if (pos.X >= Console.BufferWidth - 50 && i == 1)
                {
                    a = 4;
                }
                else if (pos.X <= 25 && i == 3)
                {
                    a = 4;
                }
                else if (pos.Y >= Console.BufferHeight - 50 && i == 2)
                {
                    a = 4;
                }
                else if (pos.Y <= 50 && i == 0)
                    a = 4;
                else
                    a = i;
                b[i] = a;

            }

            return b;
        }

        public void MakeCell() 
        {
            var rand = new Random();


            


            var pos = new Position[4];
            pos[0] = new Position(3,3);
            pos[1] = new Position(Console.BufferWidth - squareWidth - 3, 3);
            pos[2] = new Position(3,Console.BufferHeight - squareHeight - 3);
            pos[3] = new Position(Console.BufferWidth - squareWidth - 3, Console.BufferHeight - squareHeight - 3);
            
            /*/
                base conrner squares
            /*/
            makeSquare(pos[0]);
            makeSquare(pos[1]);
            makeSquare(pos[2]);
            makeSquare(pos[3]);

            int j = 0;
            byte dir = 0;

            var doordir = new List<byte>();
          
            for (int i = 0; i < 8; i++)
			{
                
                foreach (var b in DirectionsAllowed(pos[j]))
	            {
		            if(b != 4)
                        doordir.Add(b);
	            }


                dir = doordir[rand.Next(2)];
                var p = MakeCorridor(dir, MakeDoor(dir, pos[j]), 20);

                doordir.Clear();
                if(j>=3)
                    j = 0;
                else
                    j++;

			}
           
        }

        public Position Direction(byte dir, Position pos, bool revert = false)
        {
            int addX = 0;
            int addY = 0;

            switch (dir)
            {
                case 0:
                    addY = -1;
                    break;
                case 1:
                    addX = 1;
                    break;
                case 2:
                    addY = 1;
                    break;
                case 3:
                    addX = -1;
                    break;

            }

            if (revert)
            {
                addX *= -1;
                addY *= -1;
            }
            pos.X += addX;
            pos.Y += addY;

            return pos;
        }
        public void RemoveStackedPart(Position pos) //because of collition, it only checks the first index that hits in the same position and return the entity type 
        {
            for (int i = 0; i < walls.Count; i++)
            {
                if (walls[i].pos.X == pos.X && walls[i].pos.Y == pos.Y) 
                {
                    walls.RemoveAt(i);
                }
            }
        }
        // makes square, light edition (because the version before toke around 50 lines of code)
        public void makeSquare(Position offset) 
        {
            short temp = 0;


            for (int i = 0; i < squareWidth; i++)
            {

                walls.Add(new Entity(gui.ByteCode(205), new Position(offset.X+temp, offset.Y)));
                walls.Add(new Entity(gui.ByteCode(205), new Position(offset.X+temp, offset.Y+squareHeight)));                
                
                temp++;
            }
            temp = 0;

            for (int j = 0; j < squareHeight; j++)
            {
                walls.Add(new Entity(gui.ByteCode(186), new Position(offset.X, offset.Y + temp)));
                walls.Add(new Entity(gui.ByteCode(186), new Position(offset.X + squareWidth, offset.Y + temp)));
                temp++;
            }

            RemoveStackedPart(offset);
            walls.Add(new Entity(gui.ByteCode(201), offset));

            RemoveStackedPart(new Position(offset.X + squareWidth, offset.Y));
            walls.Add(new Entity(gui.ByteCode(187), new Position(offset.X + squareWidth, offset.Y)));

            RemoveStackedPart(new Position(offset.X, offset.Y + squareHeight));
            walls.Add(new Entity(gui.ByteCode(211), new Position(offset.X, offset.Y + squareHeight)));

            RemoveStackedPart(new Position(offset.X + squareWidth, offset.Y + squareHeight));
            walls.Add(new Entity(gui.ByteCode(188), new Position(offset.X + squareWidth, offset.Y + squareHeight)));
        }
        //generates door, need to have same offset as the cell it targets to be in
        public Position MakeDoor(byte dir, Position offset) 
        {
            var pos = new Position();
            switch (dir)
            {
                case 0:
                    pos = new Position( offset.X + squareWidth / 2, offset.Y);
                    break;
                case 1:
                    pos = new Position(offset.X + squareWidth, offset.Y + squareHeight / 2);
                    break;
                case 2:
                    pos = new Position(offset.X + squareWidth / 2, offset.Y + squareHeight);
                    break;
                case 3:
                    pos = new Position(offset.X, offset.Y + squareHeight / 2);
                    break;
                
            }
            RemoveStackedPart(pos);
            if(dir != 4)
                walls.Add(new Entity(gui.ByteCode(68), pos, EntityType.Door));
            return pos;
        }
        //generates a corridor, it automaticly checks what characters to use etc. only need to care about direction length and startpos
        public Position MakeCorridor(byte dir, Position pos, int length) 
        {
            var c = gui.ByteCode(186);
            if (dir == 1 || dir == 3)
                c = gui.ByteCode(205);

            for (int i = 0; i < length; i++)
            {
                if(i == 0)
                {
                    
                    if (dir == 3) 
                    {                  
                        walls.Add(new Entity(gui.ByteCode(185), new Position(pos.X, pos.Y - 1)));
                        walls.Add(new Entity(gui.ByteCode(185), new Position(pos.X, pos.Y + 1)));
                    }
                    else if (dir == 0)
                    {
                        walls.Add(new Entity(gui.ByteCode(202), new Position(pos.X-1, pos.Y)));
                        walls.Add(new Entity(gui.ByteCode(202), new Position(pos.X+1, pos.Y)));

                    }
                    else if (dir == 2)
                    {
                        walls.Add(new Entity(gui.ByteCode(203), new Position(pos.X - 1, pos.Y)));
                        walls.Add(new Entity(gui.ByteCode(203), new Position(pos.X + 1, pos.Y)));
                    }
                    else if (dir == 1) 
                    {
                        walls.Add(new Entity(gui.ByteCode(204), new Position(pos.X, pos.Y - 1)));
                        walls.Add(new Entity(gui.ByteCode(204), new Position(pos.X, pos.Y + 1)));
                    }


                }
                else if (dir == 1 || dir == 3)
                {
                    walls.Add(new Entity(c, new Position(pos.X, pos.Y - 1)));
                    walls.Add(new Entity(c, new Position(pos.X, pos.Y + 1)));
                }
                else
                {
                    walls.Add(new Entity(c, new Position(pos.X+1, pos.Y )));
                    walls.Add(new Entity(c, new Position(pos.X-1, pos.Y )));
 
                }
                pos = Direction(dir, pos);
            }
            return pos;
        }

    }
}
